package com.xishu.controller;

import com.xishu.annotation.valid.MethodValidator;
import com.xishu.entity.customer.Customer;
import com.xishu.entity.customer.ScoreShop;
import com.xishu.entity.shop.DiscountTicket;
import com.xishu.response.ResponseData;
import com.xishu.response.VerifyUtil;
import com.xishu.service.*;
import com.xishu.util.DateUtil;
import com.xishu.util.Tools;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.xishu.config.Constant.CUSTOMER_LOCK_PREFIX;
import static com.xishu.config.Constant.SCORE_HISTORY_TYPE_CUT;
import static com.xishu.response.ResponseStatus.SCORE_NOT_ENOUGH;

/**
 * 积分商城
 */
@Api(description = "积分商城")
@RestController
public class ScoreShopController implements Tools {
    private static Logger logger = LoggerFactory.getLogger(ScoreShopController.class);
    private CustomerService customerService = CustomerService.getInstance();
    private CompanyService companyService = CompanyService.getInstance();
    private CommonService commonService = CommonService.getInstance();
    private LockService localLockService = LockService.getInstance();

    @ApiOperation(value = "创建积分商城")
    @PostMapping(value = ("/score/shop"), produces = ("application/json;charset=UTF-8"))
    public ResponseData create(@RequestBody ScoreShop scoreShop) throws Exception {
        Long companyId = scoreShop.getCompanyId();
        companyService.findCompanyById(companyId);
        Long ticketId = scoreShop.getTicketId();
        VerifyUtil.verify(() -> ticketId != null);
        DiscountTicketService.getInstance().isOnlineTicket(ticketId);
        Integer score = scoreShop.getScore();
        VerifyUtil.verify(() -> getInt(score) > 0);
        VerifyUtil.verify(() -> companyService.ownTicket(ticketId));

        return commonService.createObject(scoreShop);
    }

    @ApiOperation(value = "修改积分商城")
    @PutMapping(value = ("/score/shop/modify"), produces = ("application/json;charset=UTF-8"))
    public ResponseData modify(@RequestBody ScoreShop scoreShop) throws Exception {
        Long scoreShopId = scoreShop.getId();
        ScoreShop scoreShopInDb = commonService.findEntity(scoreShopId, ScoreShop.class);
        VerifyUtil.verify(() -> companyService.ownTicket(scoreShopInDb.getTicketId()));

        return commonService.modifyObject(scoreShop);
    }

    @ApiOperation(value = "删除积分商城")
    @DeleteMapping(value = ("/score/shop"), produces = ("application/json;charset=UTF-8"))
    public ResponseData delete(@RequestBody ScoreShop scoreShop) throws Exception {
        Long scoreShopId = scoreShop.getId();
        ScoreShop scoreShopInDb = commonService.findEntity(scoreShopId, ScoreShop.class);
        VerifyUtil.verify(() -> companyService.ownTicket(scoreShopInDb.getTicketId()));

        return commonService.delete(scoreShop);
    }

    @ApiOperation(value = "查询积分商城")
    @PutMapping(value = ("/score/shop"), produces = ("application/json;charset=UTF-8"))
    @MethodValidator(mustLogin = false)
    public ResponseData search(@RequestBody ScoreShop scoreShop) throws Exception {
        Long companyId = scoreShop.getCompanyId();
        VerifyUtil.verify(() -> companyId != null);

        return commonService.searchResponse(scoreShop, (s) -> {
            try {
                Long ticketId = s.getTicketId();
                Optional<DiscountTicket> optionalDiscountTicket = DiscountTicketService.getInstance().findTicketOptional(ticketId);
                if (optionalDiscountTicket.isPresent()) {
                    DiscountTicket discountTicket = optionalDiscountTicket.get();
                    s.setTicketName(discountTicket.getName());
                    s.setTicketName_zh(DiscountTicketService.getInstance().getTicketNameZh(discountTicket));
                    s.setTicketName_en(DiscountTicketService.getInstance().getTicketNameEn(discountTicket));

                    if (discountTicket.getBindingDays() > 0) {
                        discountTicket.setEndTime(DateUtil.endTimeInDay(System.currentTimeMillis() + discountTicket.getBindingDays() * DateUtil.ONE_DAY));
                        discountTicket.setExpiredTime(discountTicket.getEndTime());
                    } else {
                        discountTicket.setExpiredTime(discountTicket.getEndTime());
                        if (discountTicket.getEndTime() < System.currentTimeMillis()) {
                            s.setExpired(true);
                        }
                    }

                    DiscountTicketService.getInstance().addCompanyMainItemList(discountTicket);

                    s.setDiscountTicket(discountTicket);
                } else {
                    commonService.delete(s);
                }
            } catch (Exception e) {
                logger.error("e", e);
            }
        }, (list) -> {
            //C端只需返回没过期的，并且传了expired字段
            if (isNotEmpty((scoreShop.getExpired())) && scoreShop.getExpired() == false) {
                return list.stream().filter(p -> isNotEmpty(p.getTicketName()) && !getBoolean(p.getDiscountTicket().getExpired())).collect(Collectors.toList());
            }
            //管理端过不过期都返回，没传expired字段
            return list.stream().filter(p -> isNotEmpty(p.getTicketName())).collect(Collectors.toList());
        });
    }

    @ApiOperation(value = "积分兑换, id是scoreShop的ID")
    @PutMapping(value = ("/score/shop/exchange"), produces = ("application/json;charset=UTF-8"))
    @MethodValidator(mustLogin = false)
    public ResponseData exchangeScore(@RequestBody ScoreShop scoreShop) throws Exception {
        //需要添加单个用户的并发限制
        Long customerId = scoreShop.getCustomerId();
        VerifyUtil.verify(() -> customerId != null);

        Object lock = localLockService.getLock(CUSTOMER_LOCK_PREFIX + customerId);
        synchronized (lock) {
            Customer customer = customerService.findCustomer(customerId);

            if (isEmpty(scoreShop.getIds())) {
                List<Long> scoreShopIds = new ArrayList<>();
                scoreShopIds.add(scoreShop.getId());
                scoreShop.setIds(scoreShopIds);
            }

            List<Long> scoreShopIds = scoreShop.getIds();

            VerifyUtil.verify(() -> isNotEmpty(scoreShopIds));
            //判斷會員的積分是否夠用
            int totalCostScore = scoreShopIds.stream().mapToInt(p -> {
                try {
                    return customerService.findScoreShop(p).get().getScore();
                } catch (Exception e) {
                    logger.error("e", e);
                    return 0;
                }
            }).sum();

            VerifyUtil.verify(() -> getInt(customer.getScore()) >= totalCostScore, SCORE_NOT_ENOUGH);

            for (Long scoreShopId : scoreShop.getIds()) {
                Optional<ScoreShop> scoreShopOptional = customerService.findScoreShop(scoreShopId);
                VerifyUtil.verify(() -> scoreShopOptional.isPresent());
                DiscountTicketService discountTicketService = DiscountTicketService.getInstance();
                ScoreShop scoreShopInDb = scoreShopOptional.get();
                Long ticketId = scoreShopInDb.getTicketId();
                DiscountTicket ticket = discountTicketService.findTicket(ticketId, true);

                //判断用户的积分是否够用
                Integer score = getInt(scoreShopInDb.getScore());
                VerifyUtil.verify(() -> score > 0);
                VerifyUtil.verify(() -> getInt(customer.getScore()) >= score, SCORE_NOT_ENOUGH);

                //积分兑换的优惠券均是一次性使用，而且不是VIP类型的优惠券
                CustomerTaskService.getInstance().addTicketToCustomer(customer, ticket, false, true);

                //修改会员的积分
                int customerScore = customer.getScore() - score;
                customer.setScore(customerScore);
                commonService.save(customer);

                //添加用户的积分兑换历史
                customerService.addScoreHistory(customer.id, SCORE_HISTORY_TYPE_CUT, -score, null, null);
            }

            return ResponseData.emptyResponse();
        }
    }
}
